package Thread;

//写一个简单的线程池(更高效地利用多线程完成一系列的操作)
//直接写一个固定数目的线程池，暂时不考虑线程的增加和减少
//1)提供构造方法，指定创建多少个线程
//2）在构造方法中，把这些线程都创建好
//3)有一个阻塞队列，能够持有要执行的任务
//4)提供submit方法，可以添加新的任务

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

class  MyThreadPoolExecutor{
    //用来保存任务的队列
    private List<Thread> threadList=new ArrayList<>();
    //通过n指定创建多少个线程
    private BlockingDeque<Runnable> queue=new LinkedBlockingDeque<>(1000);
    public MyThreadPoolExecutor(int n){
        for (int i = 0; i < n; i++) {
            Thread t=new Thread(()->{
                //线程要做的事情就是把队列中的任务不停的取出来，并且进行执行
                while(true) {
                    Runnable runnable;
                    //此处的take带有阻塞功能
                    //如果队列为空，此处的take就会阻塞
                    try {
                        runnable = queue.take();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    //取出一个任务就执行一个任务即可
                    runnable.run();
                }
            });
            t.start();
            threadList.add(t);
        }
    }
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
}

public class ThreadDemo29 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPoolExecutor executor = new MyThreadPoolExecutor(4);
        for (int i = 0; i < 1000; i++) {
            int n = i;
            //此处的n是一个“事实final”变量
            //每次循环，都是一个新的n，n本身没有改变，就可以被捕获了
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    //System.out.println("执行任务" + i + " , 当前线程为: " + Thread.currentThread().getName());
                    //上面那样写是会报错的，变量捕获要保证i不变，但是i会改变
                    //回调函数访问当前外部作用域的变量就是变量捕获
                    System.out.println("执行任务" + n + " , 当前线程为: " + Thread.currentThread().getName());
                }
            });
        }
    }
}

//关于执行效果，多个线程间的执行是不确定的，某个线程取到了某个任务，但是并非立即执行，这个过程中另一个线程就插到前面了
